import { inject, provide, reactive, ref, h } from 'vue'
import { sendServiceData } from '../service'
import {
    copyObjectSameTo, deepCopyObject, hasOwnProp,
    popAskWin2,
    popMessage
} from '../utils/normalUtils'
import { getServiceErrorMsg } from '../service/base/request'
import { ElMessageBox } from 'element-plus'
import DeletePop from '../../components/normal/DeletePop.vue'
import { IPageData, usePageQuery } from './PageQuery'
import { LIST_ALL_VALUE } from '../manager/appConstManager'


export const formWinEmits = ['success']

export const formWinProps = {
    // 是否编辑状态
    isEdit: {
      type: Boolean,
      default: false
    },
    // 编辑对象
    editData: {
        type: Object,
        default: function() {
            return null
        }
    }
}

/**
 * 询问接口调用
 * @param deleteMethod
 * @param sendData
 * @param stateProxy
 * @param msg
 */
export async function askWinExecute(deleteMethod:any, sendData: any, stateProxy:any = null, msg = '是否确认删除?') {
    await popAskWin2(msg)
    const result = await sendServiceData(deleteMethod, sendData, stateProxy)
    return result
}

/**
 * 强制删除提示窗口
 * @param message
 * @param checkLabel
 */
export function popForceDeleteWin(message = '是否确认删除对象?', checkLabel = '强制删除') {
    const checked = ref<boolean | string | number>(false)
    return new Promise((resolve, reject) => {
        ElMessageBox({
            title: '',
            showCancelButton: true,
            cancelButtonText: '取消',
            confirmButtonText: '确定',
            message: () =>
                h(DeletePop, {
                    message,
                    checkLabel,
                    modelValue: checked.value,
                    'onUpdate:modelValue': (val: boolean | string | number) => {
                        checked.value = val
                    }
                })
        }).then(() => {
            resolve(checked.value)
        }).catch(() => {
            // eslint-disable-next-line prefer-promise-reject-errors
            reject()
        })
    })
}

/**
 * 控制状态对象
 */
export class PopState {
    isLoading = false
    // 是否弹出编辑窗口
    isPopEdit = false
    // 是否弹出创建窗口
    isPopCreate = false
    // 是否弹出详情窗口
    isPopDetail = false
    // 弹出窗口总状态
    isPop = false
    params:any = null
    // 可绑定的编辑对象
    editData:any = null
    // 查询条件
    search:any = reactive({})
    // 默认列表
    dataListSource:any[] = []
    // 多选对象
    checkDataSource:any[] = []

    /**
     * 其他弹出
     */
    popWin:any = reactive({})

    detailMethod = null
    updateMethod = null
    createMethod = null
}

/**
 * 窗口特别多的时候用
 * @param popWins
 */
export function usePopState(popWins:string[]) {
    const obj: any = {}
    for (const att of popWins) {
        obj[att] = false
    }
    const popWinState = reactive(obj)
    const popWinActions = {
        open(win: string, value = true) {
            popWinState[win] = value
        },
        close(win: string) {
            popWinState[win] = false
        }
    }
    return {
        popWinState,
        popWinActions
    }
}

/**
 * 表单验证
 * @param formViewRef
 */
export function validFormRef(formViewRef:any):Promise<boolean> {
    return new Promise((resolve) => {
        formViewRef.value.validate().then(() => {
            resolve(true)
        }).catch((ev:any) => {
            resolve(false)
        })
    })
}

/**
 * 验证表单
 */
export function validFormThen(formRef:any, callBack:any) {
    validFormRef(formRef).then((val:boolean) => {
        if (val)callBack()
    })
}


/**
 * 表单验证
 * @param formViewRef
 */
export function validFormRefResult(formViewRef:any):Promise<any> {
    return new Promise((resolve) => {
        formViewRef.value.validate().then(() => {
            resolve(null)
        }).catch((ev:any) => {
            resolve(ev)
        })
    })
}

/**
 * 表单验证 - 某项
 * @param formViewRef
 * @param field
 */
export async function validateRefField(formViewRef:any, field:string) {
    let validResult = false
    await formViewRef.value.validateField(field, (valid:any) => {
        validResult = valid
    })
    return validResult
}

/**
 * 表单验证
 * @param formViewRef
 * @param fields
 */
export async function validateRefFields(formViewRef:any, fields:string[]) {
     for (const item of fields) {
         const result = validateRefField(formViewRef, item)
         if (!result) return false
     }
     return true
}

const joinObjectValue = (objA:any, objB:any) => {
    for (const att in objB) {
        if (!hasOwnProp(objA, att)) { objA[att] = objB[att] }
    }
}

/**
 *
 * @param provideName
 */
export function useInjectPopState(provideName:any = 'popWinPm') {
    const winPm:any = inject(provideName)
    return {
        rootPopState: winPm ? winPm.popState : new PopState()
    }
}


// ####################################################################### provider #########################################################

/**
 *
 */
export interface IPopWinStateOptions {
    queryMethod?: any,
    deleteMethod?: any,
    updateMethod?: any,
    detailMethod?: any,
    params?: any,
    forceDelete?: boolean, // 统一强制删除逻辑
    forceField?: string,
    page?: boolean,
    pageOptions?:any
    deletePatch?: boolean,
    popWin?: string[],
    search?: any,
    idField?:string,
}

/**
 *
 * @param options
 * @param provideName
 */
export function usePopWinProvide(options:IPopWinStateOptions|null = null, provideName = 'popWinPm') {
    return usePopWinState(options, provideName)
}

/**
 * 表单窗口
 * @param options
 * @param provideName
 */
export function usePopWinState(options:IPopWinStateOptions|null = null, provideName = '') {
    const state:PopState = reactive(new PopState())
    // 实例对象
    const instance:any = {
        queryMethod: null,
        deleteMethod: null,
        updateMethod: null,
        detailMethod: null,
        params: null,
        forceDelete: false, // 统一强制删除逻辑
        forceField: 'isForce',
        idField: 'id',
        page: false,
        pageOptions: null,
        deletePatch: true // 相同批量模式删除接口
    }
    // 先留着
    let pagePM: any = null
    let pageInstance:any = null
    // 初始化
    if (options) {
        Object.assign(instance, options)
        // 管理其他弹出框
        if (options.popWin) {
            for (const win of options.popWin) {
                state.popWin[win] = false
            }
        }
        if (options.search) {
            state.search = options.search
        }
    }
    // 分页查询
    if (instance.page) {
        // 列表
        pageInstance = usePageQuery({
            queryMethod: instance.queryMethod,
            ...(instance.pageOptions || {})
        })
        pagePM = pageInstance.actions
    }
    // 操作
    const actions = {

        /**
         * 返回结果单条处理(resultItem:any):void
         */
        itemRender: null,

        /**
         * 返回结果整个处理 (result:any):any[]
         */
        listResult: null,

        /**
         *  创建 popState.editData
         */
        popCreate(params:any = null) {
            state.editData = params
            Object.assign(state, {
                isPopEdit: false,
                isPopCreate: true,
                isPopDetail: false,
                isPop: true
            })
            actions.popHandler(params, 'create')
        },

        /**
         * 编辑
         * @param item
         */
        popEdit(item: any) {
            state.editData = item
            Object.assign(state, {
                isPopEdit: true,
                isPopCreate: false,
                isPopDetail: false,
                isPop: true
            })
            actions.popHandler(item, 'edit')
        },

        /**
         * 详情
         * @param item
         */
        popDetail(item: any) {
            state.editData = item
            Object.assign(state, {
                isPopEdit: false,
                isPopCreate: false,
                isPopDetail: true,
                isPop: false
            })
            actions.popHandler(item, 'detail')
        },

        /**
         * 弹出处理
         * @param item
         * @param type
         */
        popHandler(item: any, type = '') {

        },

        /**
         * 弹出窗体 主要other使用
         * @param type
         * @param params
         */
        pop(type:string, params:any = null) {
            state.editData = params
            state.popWin[type] = true
        },

        /**
         * 关闭窗体
         */
        close() {
            actions.closeExecute()
        },
        /**
         * 关闭窗体
         */
        closeExecute() {
            Object.assign(state, {
                isPopEdit: false,
                isPopCreate: false,
                isPopDetail: false,
                isPop: false,
                editData: null
            })
            for (const att in state.popWin) {
                state.popWin[att] = false
            }
        },

        /**
         * 操作成功后处理
         * @param data
         * @param req
         * @param message
         */
        success(data:any = null, req = true, message = '操作成功') {
            // 提示信息
            if (message) popMessage(message)
            // 关闭窗口
            actions.close()
            // 重新查询
            if (req)actions.reQuery()
            // 扩展回调
            actions.successHandler(data)
        },

        // 扩展
        successHandler(data:any) {

        },

        // --------------------------------------------------------------------------- list -----------------------------------------

        /**
         * 查询列表
         * @param params
         */
        async queryList(params: any = null) {
            const result = await actions.executeQueryList(params)
            return result
        },

        /**
         * 执行查询 方便覆盖留一个执行方法
         * @param params
         * @param itemRenderFunc
         * @param listRenderFunc
         */
        async executeQueryList(params: any = null, itemRenderFunc:any = null, listRenderFunc:any = null) {
            if (itemRenderFunc)actions.itemRender = itemRenderFunc
            if (listRenderFunc)actions.listResult = listRenderFunc
            const send = filterSearch(deepCopyObject(params || state.search))
            if (pagePM) {
                await pagePM.queryList(send || {}, actions.listResult, actions.itemRender)
                return pagePM.pageData.dataSource
            } else if (instance.queryMethod) {
                const result = await sendServiceData(instance.queryMethod, send, state)
                let list = result || []
                // 整个返回结果处理
                if (actions.listResult) {
                    const resultRenderFunc:any = actions.listResult
                    list = resultRenderFunc(result)
                }
                // 单条处理
                if (actions.itemRender) {
                    list.forEach((item: any) => {
                        const itemRenderFunc:any = actions.itemRender
                        itemRenderFunc(item)
                    })
                }
                state.dataListSource = list
                return list
            }
            return []
        },

        /**
         * 重新查询
         * @param params
         */
        async reQuery(params: any = null) {
            await actions.queryList()
        },

        /**
         * 选中数据变化
         * @param items
         */
        checkDataHandler(items:any[]) {
            state.checkDataSource = items
        },

        /**
         * 删除某个对象
         * @param item
         * @param isMore
         * @param ask
         * @param moreSend
         */
        async deleteItem(item: any, isMore = false, ask = true, moreSend = true) {
            if (instance.deletePatch) {
                item = isMore ? item : [item]
                moreSend = true
            }
            const params: any = actions.getDeleteParams(item, isMore, moreSend)
            let result = null
            if (instance.forceDelete) {
                const isForce = await popForceDeleteWin()
                if (isForce)result = await actions.forceDeleteItem(params)
                else result = await sendServiceData(instance.deleteMethod, params, state)
            } else {
                await popAskWin2('是否确认删除?')
                result = await sendServiceData(instance.deleteMethod, params, state)
            }
            actions.deleteResultHandler(result)
        },

        /**
         * 执行删除 如果指定强制删除 删除失败强制删除
         * @param params
         * @param resultHandler
         */
         executeDelete(params:any, resultHandler:any) {
            state.isLoading = true;
            (instance.deleteMethod as any)(params)
                .then((result: any) => {
                    state.isLoading = false
                    resultHandler(result)
                })
                .catch(async (res: any) => {
                    state.isLoading = false
                    await actions.deleteErrorHandler(res, params, resultHandler)
                })
        },

        /**
         * 删除错误处理
         * @param error
         * @param params
         * @param resultHandler
         */
        async deleteErrorHandler(error:any, params:any, resultHandler:any) {
            if (!instance.forceDelete || !actions.isForceState(error)) {
                popMessage(getServiceErrorMsg(error))
                return
            }
            await popAskWin2(getServiceErrorMsg(error))
            const result = await actions.forceDeleteItem(params)
            resultHandler(result)
        },

        /**
         * 是否是强制执行的错误
         * @param res
         */
        isForceState(res:any) {
          return res.data && res.data.code === 'BIZ_ERROR'
        },

        /**
         * 强制删除执行
         * @param params
         */
        async forceDeleteItem(params:any) {
            const send = { ...params }
            send[instance.forceField] = true
            const result = await sendServiceData(instance.deleteMethod, send, state)
            return result
        },


        /**
         * 删除多个
         */
        async deleteItems(items: any[]|null = null): Promise<void> {
            if (!items)items = state.checkDataSource || []
            if (items.length === 0) return
            await actions.deleteItem(state.checkDataSource, true)
        },

        /**
         * 获得删除参数 默认多个逗号分隔
         * @param data
         * @param isMore
         * @param moreSend
         */
        getDeleteParams(data: any, isMore = false, moreSend = false): any {
            if (isMore || moreSend) return data.map((item: any) => item[instance.idField])
            return { id: data[instance.idField] }
        },

        /**
         * 删除返回处理
         * @param result
         * @param oldData
         */
        deleteResultHandler(result: any, oldData: any = null) {
            popMessage('操作成功！', 'success')
            actions.reQuery()
        },

        /**
         * 获取选中的id
         */
        getCheckIds() {
            if (!state.checkDataSource || state.checkDataSource.length === 0) return []
            return state.checkDataSource.map((item) => item[instance.idField])
        }
    }

    // 控制对象
    const control = {
        popWin: state.popWin,
        popState: state,
        actions,
        instance,
        pageInstance,
        pageData: pageInstance ? pageInstance.pageData : null,
        pageActions: pageInstance ? pageInstance.actions : null
    }
    // 注入控制对象
    if (provideName)provide(provideName, control)
    return control
}

/**
 * 为空 就是不传
 * @param search
 */
export function filterSearch(search:any, clearBlank = true) {
    for (const att in search) {
        if (search[att] === LIST_ALL_VALUE) delete search[att]
        if (clearBlank && (search[att] === '' || search[att] === null)) delete search[att]
    }
    return search
}


// ################################################################################ inject formData #############################################
export interface IRootInjectOptions {
    createMethod?: any,
    updateMethod?: any,
    detailMethod?: any,
    params?: any,
    [props:string]:any
}
/**
 *
 * @param viewState
 * @param options
 * @param provideName
 */
export function useInjectRootState(viewState:any = null, options:IRootInjectOptions|null = null, provideName:any = 'popWinPm') {
    // 根控制模型
    let winPm:any = null
    if (provideName) {
        if (typeof provideName === 'string')winPm = inject(provideName)
        else winPm = provideName
    }
    // 初始化状态
    if (viewState) {
        if (!hasOwnProp(viewState, 'isLoading'))viewState.isLoading = false
        if (!hasOwnProp(viewState, 'formData'))viewState.formData = {}
    }
    // 窗口状态
    let popState:PopState = reactive(new PopState())
    let instance = {
        createMethod: null,
        updateMethod: null,
        detailMethod: null,
        params: null
    }
    if (options) copyObjectSameTo(options, popState)
    if (winPm) {
        popState = winPm.popState
        instance = winPm.instance
    }
    if (options)Object.assign(instance, options)
    return {
        root: winPm,
        viewState,
        rootActions: winPm ? winPm.actions : null,
        rootPopState: popState,
        popState,
        instance,
        winPm
    }
}

/**
 * 表单处理
 */
export function useFormData(viewState:any = null, options:any = null, provideName:any = '') {
    // 表单对象
    const formRef = ref()
    const { winPm, popState, instance } = useInjectRootState(viewState, options, provideName)
    const formOptions = { idField: 'id' }
    if (options) Object.assign(formOptions, options)
    // changed flag
    let _changed = false

    // 执行
    const actions = {
        /**
         * 验证表单
         */
        async validForm() {
            const result = await validFormRef(formRef)
            return result
        },

        /**
         * 验证表单
         */
        validFormThen(callBack:any) {
            validFormRef(formRef).then((val:boolean) => {
                if (val)callBack()
            })
        },

        /**
         * 获取验证信息
         */
        async getFormValidError() {
            const result = await validFormRefResult(formRef)
            return result
        },

        /**
         * 表单提交处理
         * @param formData
         * @param copy
         * @param isId
         * @param hidden
         */
        async submitHandler(formData:any = null, copy = false, isId = false, hidden = true) {
            // 验证表单
            const validError = await actions.getFormValidError()
            if (validError) return false
            // 参数
            if (!formData)formData = viewState.formData || {}
            const send = !isId ? actions.getSubmitData(formData) : actions.getSubmitDataId(formData)
            // 提交数据
            const result:any = await sendServiceData(popState.isPopEdit ? instance.updateMethod : instance.createMethod, send, viewState)
            // 处理成功
            actions.submitSuccess(result, hidden)
            return result || true
        },


        /**
         * 保存并继续
         * @param formData
         * @param copy
         * @param isId
         */
        async submitNextHandler(formData:any = null, copy = false, isId = false, msg = '添加成功！') {
            const result = await actions.submitHandler(formData, copy, isId, false)
            if (!result) return
            if (msg) popMessage(msg, 'success')
            actions.resetNextForm()
        },

        /**
         * 重置表单
         */
        resetNextForm() {

        },

        /**
         * 单独抽个函数
         * @param formData
         * @param copy
         */
        getSubmitData(formData:any = null, copy = false) {
            return actions.getSubmitDataExecute(formData, copy)
        },

        /**
         *
         * @param formData
         * @param copy
         */
        getSubmitDataExecute(formData:any = null, copy = false) {
            return actions.copySubmitFormData(formData, copy)
        },

        /**
         *
         * @param formData
         * @param copy
         */
        copySubmitFormData(formData:any = null, copy = false) {
            if (!formData)formData = viewState.formData || {}
            let send:any = { [formOptions.idField]: '' }
            if (copy)send = deepCopyObject(formData)
            else Object.assign(send, formData)
            if (!popState.isPopEdit && hasOwnProp(send, formOptions.idField)) {
                delete send[formOptions.idField]
            }
            return send
        },

        /**
         * 单独抽个函数有id
         * @param formData
         * @param copy
         */
        getSubmitDataId(formData:any = null, copy = false) {
            if (!formData)formData = viewState.formData || {}
            let send:any = { }
            if (copy)send = deepCopyObject(formData)
            else Object.assign(send, formData)
            return send
        },


        /**
         * 成功处理
         * @param result
         * @param hidden
         */
        submitSuccess(result:any, hidden = true) {
            if (!hidden)_changed = true
            else if (winPm)winPm.actions.success(result)
        },

        /**
         * 初始化
         * @param query
         * @param params
         */
        async initFormData(query = false, params:any = null) {
            if (popState.isPopEdit) actions.initEdit(query, params)
            else if (popState.isPopCreate) actions.initCreate(params)
        },

        /**
         * 编辑表单
         * @param query
         * @param params
         * @param detailId
         */
        async initEdit(query = false, params:any = null, detailId = 'id') {
            if (query) await actions.queryDetail(popState.editData, params, true, detailId)
            else copyObjectSameTo(popState.editData || {}, viewState.formData)
        },

        /**
         * 创建表单
         */
        async initCreate(params:any = null) {

        },

        /**
         * 查询详情
         * @param data
         * @param params
         * @param init
         * @param detailId
         */
        async queryDetail(data:any, params:any = null, init = true, detailId = 'id') {
            const send = params || { id: data[detailId] }
            const result:any = await sendServiceData(instance.detailMethod, send, viewState)
            actions.handlerDetail(result, init)
            return result
        },

        /**
         *
         * @param result
         * @param init
         */
        handlerDetail(result:any, init = true) {
            if (result && init)copyObjectSameTo(result, viewState.formData)
        },

        close() {
            if (winPm)winPm.actions.close(_changed)
            _changed = false
        }
    }

    return {
        formRef,
        actions,
        root: winPm,
        viewState,
        rootActions: winPm ? winPm.actions : null,
        rootPopState: popState,
        popState,
        instance,
        options: instance
    }
}

/**
 * 只拷贝基本数据 非结构化类
 * @param obj
 */
export function copyFormData(obj:any):any {
    const re:any = {}
    for (const att in obj) {
        re[att] = copyFormItem(obj[att])
    }
    return re
}

/**
 * 表单数据拷贝 会控制级别
 * @param value
 */
function copyFormItem(value:any):any {
    if (value instanceof Date) return new Date(value.getTime())
    else if (Array.isArray(value)) return value.map((item) => copyFormItem(item))
    else if (typeof value === 'object') return copyFormData(value)
    return value
}

/**
 *
 * @param viewState
 * @param options
 * @param provideName
 */
export function usePopWinInject(viewState:any = null, options:any = null, provideName = 'popWinPm') {
    return useFormData(viewState, options, provideName)
}
